package com.rf.richfitwheel.dyn.business.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.rf.richfitwheel.admin.utils.UserUtil;
import com.rf.richfitwheel.common.contants.Constant;
import com.rf.richfitwheel.common.exception.BusinessException;
import com.rf.richfitwheel.common.utils.PageParameter;
import com.rf.richfitwheel.common.utils.R;
import com.rf.richfitwheel.common.utils.UuidUtil;
import com.rf.richfitwheel.dyn.business.constants.DataBaseColumnType;
import com.rf.richfitwheel.dyn.business.constants.DynamicBusinessConstants;
import com.rf.richfitwheel.dyn.business.entity.*;
import com.rf.richfitwheel.dyn.business.mapper.MysqlDynamicMapper;
import com.rf.richfitwheel.dyn.business.service.GenerateIDUtil;
import com.rf.richfitwheel.dyn.business.service.SysApiSendHisService;
import com.rf.richfitwheel.dyn.business.service.SysBusinessDesignerService;
import com.rf.richfitwheel.dyn.business.service.SysBusinessDynamicService;
import com.rf.richfitwheel.workflow.entity.WfTaskParam;
import com.rf.richfitwheel.workflow.feignclient.FWfTaskService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SysBusinessDynamicServiceImpl extends ServiceImpl<MysqlDynamicMapper, SysBusinessCommon> implements SysBusinessDynamicService {
    private static final Logger log = LoggerFactory.getLogger(SysBusinessDynamicServiceImpl.class);
    @Resource
    private SysBusinessDesignerService sysBusinessDesignerService;
    @Resource
    private FWfTaskService fWfTaskService;
    @Resource
    private SysApiSendHisService sysApiSendHisService;
    @Resource
    private GenerateIDUtil redisGenerateIDUtil;
    /**
     * 分页查询动态表数据
     *
     * @param parameter 参数
     * @return 分页数据
     */
    @Override
    public Page<Row> queryByPage(PageParameter<BusinessCommonQueryParam> parameter) {
        Page<Row> page = new Page<>(parameter.getPage(), parameter.getLimit());
        BusinessCommonQueryParam param = parameter.getDataForm();
        Assert.notNull(param.getTableName(), "请传入需要查询的表名");
        QueryWrapper queryWrapper = QueryWrapper.create();
        if (param.getColumns() != null && !param.getColumns().isEmpty()) {
            queryWrapper.select(param.getColumns().toArray(new String[0]));
        }else{
            queryWrapper.select("*");
        }
        queryWrapper.from(param.getTableName());
        if (!param.getParams().isEmpty()) {
            //动态拼接查询条件
            for (BusinessCommonQueryParamColumn c : param.getParams()) {
                switch (c.getQueryType()){
                    case DataBaseColumnType.QUERY_TYPE_EQ : {
                        queryWrapper.eq(c.getColumnName(), c.getValue());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_LIKE : {
                        queryWrapper.like(c.getColumnName(), c.getValue());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_NE : {
                        queryWrapper.ne(c.getColumnName(), c.getValue());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_IN : {
                        queryWrapper.in(c.getColumnName(), c.getValue());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_LE : {
                        queryWrapper.le(c.getColumnName(), c.getValue());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_GE : {
                        queryWrapper.ge(c.getColumnName(), c.getValue());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_GT : {
                        queryWrapper.gt(c.getColumnName(), c.getValue());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_LT : {
                        queryWrapper.lt(c.getColumnName(), c.getValue());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_ISNULL : {
                        queryWrapper.isNull(c.getColumnName());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_NOTNULL : {
                        queryWrapper.isNotNull(c.getColumnName());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_NOT_IN : {
                        queryWrapper.notIn(c.getColumnName(), c.getValue());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_BETWEEN:{
                        queryWrapper.between(c.getColumnName(), c.getValue(), c.getValue2());
                    }
                    case DataBaseColumnType.QUERY_TYPE_LEFT_LIKE : {
                        queryWrapper.likeLeft(c.getColumnName(), c.getValue());
                        break;
                    }
                    case DataBaseColumnType.QUERY_TYPE_RIGHT_LIKE : {
                        queryWrapper.likeRight(c.getColumnName(), c.getValue());
                        break;
                    }
                    default : break;
                }
            }
        }

        return this.mapper.paginateAs(page, queryWrapper, Row.class);
    }

    /**
     * 动态业务（表）数据保存货提交，暂存、提交
     *
     * @param businessDynamicParam 参数
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveOrSubmitBusinessDynamic(BusinessDynamicParam businessDynamicParam) throws JsonProcessingException {
        //获取设计信息
        SysBusinessDesigner businessDesigner = sysBusinessDesignerService.getSysBusinessDesignerHasDetail(businessDynamicParam.getDesignerId());
        Date dateTime = new Date();
        if (StringUtils.isBlank(businessDynamicParam.getId())) {
            //新增数据
            ModelDataEntity mainData = getMainFormData(businessDynamicParam, dateTime);
            mainData.setTableName(businessDesigner.getMainTable());
            //主表
            this.mapper.insertData(mainData);
            //子表
            for (Map.Entry<String, List<Map<String, Object>>> entry : businessDynamicParam.getSub().entrySet()) {
                String key = entry.getKey();
                List<Map<String, Object>> value = entry.getValue();
                ModelDataEntity subData = getSubFormData(key, mainData.getDatas().get("id").toString(), value, businessDynamicParam.getDesignerId());
                this.mapper.insertDataBatch(subData);
            }
            businessDynamicParam.setId(mainData.getDatas().get("id").toString());
        }else{
            //修改数据
            ModelDataEntity mainData = getMainFormData(businessDynamicParam, dateTime);
            mainData.setTableName(businessDesigner.getMainTable());
            this.mapper.updateData(mainData);
            //删掉原先的子表再新增
            for (Map.Entry<String, List<Map<String, Object>>> entry : businessDynamicParam.getSub().entrySet()) {
                String key = entry.getKey();
                List<Map<String, Object>> value = entry.getValue();
                this.mapper.deleteDataByMainId("dyn_" + "sub_" + key, mainData.getDatas().get("id").toString());
                ModelDataEntity subData = getSubFormData(key, mainData.getDatas().get("id").toString(), value, businessDynamicParam.getDesignerId());
                this.mapper.insertDataBatch(subData);
            }
        }
        if(Constant.COMMON_YES_OR_NO_YES.equals(businessDynamicParam.getSubmit())){
            if (Constant.COMMON_YES_OR_NO_YES.equals(businessDesigner.getHasTask())) {
                //提交的情况下看有没有流程变量，和taskId，有的话就是审批，没有发起流程
                WfTaskParam taskParam = businessDynamicParam.getTaskParam();
                // 如果定义了工作流则会提交流程
                if(taskParam != null && StringUtils.isNotBlank(taskParam.getTaskId())){
//                    taskParam.setBusinessKey(businessDynamicParam.getId());
//                    taskParam.setBusinessDesignerId(businessDesigner.getId());
//                    taskParam.setBusinessDesignerCode(businessDesigner.getDesignerCode());
                    R r = fWfTaskService.submitTask(taskParam);
                    if(!"0".equals(r.getCode())){
                        throw new BusinessException(r.getMsg());
                    }
                }else{
                    taskParam = new WfTaskParam();
                    taskParam.setProcessKey(businessDesigner.getTaskDefCode());
                    taskParam.setApproveNo(redisGenerateIDUtil.generateId("DNY-BUS", "4", 10));
                    taskParam.setOrgCode(UserUtil.getUser().getDefaultOrgCode());
                    taskParam.setBusinessKey(businessDynamicParam.getId());
                    taskParam.setBusinessDesignerId(businessDesigner.getId());
                    taskParam.setBusinessDesignerCode(businessDesigner.getDesignerCode());
                    taskParam.setProcessInsName(businessDesigner.getDesignerName()+ taskParam.getApproveNo());
                    R r = fWfTaskService.submitTask(taskParam);
                    if(!"0".equals(r.getCode())){
                        throw new BusinessException(r.getMsg());
                    }
                }
            }
            if (!businessDynamicParam.getApiList().isEmpty()) {
                //调用接口
                businessDynamicParam.getApiList().forEach(api -> {
                    sysApiSendHisService.exchangeApi(api.getApiUrl(), api.getApiMethod(), api.getApiType(),
                            api.getApiHead(), api.getApiBody());
                });
            }
        }
        return true;
    }

    /**
     * 根据业务Id查询业务的表单数据
     *
     * @param parameter 参数
     * @return 数据
     */
    @Override
    public BusinessDynamicParam getDynBusinessInfoById(BusinessDynamicParam parameter) {
        //获取设计信息
        SysBusinessDesigner businessDesigner = sysBusinessDesignerService.getSysBusinessDesignerHasDetail(parameter.getDesignerId());
        QueryWrapper queryWrapper = QueryWrapper.create().from(businessDesigner.getMainTable()).eq("id", parameter.getId());
        List<Row> mainRows = this.mapper.selectRowsByQuery(queryWrapper);
        if (mainRows.isEmpty()) {
            return parameter;
        }
        Row data = mainRows.get(0);
        //转化主表数据，将key替换为表单控件名
        try {
            Map<String, Map<String, String>> tableMapping = sysBusinessDesignerService.getMainTableMappingByDesignerId(parameter.getDesignerId());
            tableMapping.get("main").forEach((key, value) -> {
                parameter.getMain().put(value, data.get(value));
            });
            if (!businessDesigner.getSubTable().isEmpty()) {
                //有子表的情况加载子表数据
                for (String subTable : businessDesigner.getSubTable().split(",")) {
                    List<Row> list = this.mapper.selectRowsByQuery(QueryWrapper.create().from(subTable)
                            .eq("main_id", parameter.getId()));
                    parameter.getSub().put(subTable, list.stream().map(row -> {
                        Map<String, Object> m = new HashMap<>();
                        tableMapping.get(subTable.replaceAll("dyn_sub_", "")).forEach((key, value) -> {
                            m.put(value, row.get(value));
                        });
                        return m;
                    }).collect(Collectors.toList()));
                }
            }
        } catch (JsonProcessingException e) {
            log.error("将ID为{}的表{}数据转换为页面数据异常", parameter.getId(), businessDesigner.getMainTable(), e);
        }
        return parameter;
    }

    /**
     * 组织业务主表数据
     * @param businessDynamicParam 参数
     * @param dateTime 操作时间
     * @return 数据
     */
    private ModelDataEntity getMainFormData(BusinessDynamicParam businessDynamicParam, Date dateTime) throws JsonProcessingException {
        Map<String, Map<String, String>> tableMapping = sysBusinessDesignerService.getMainTableMappingByDesignerId(businessDynamicParam.getDesignerId());
        ModelDataEntity mainData = new ModelDataEntity();

        Map<String, Object> datas = new HashMap<>();
        if (StringUtils.isBlank(businessDynamicParam.getId())) {
            //数据主键，新增时生成
            datas.put("id", UuidUtil.get32UUID());
            datas.put("create_user", UserUtil.getUser().getId());
            datas.put("create_time", dateTime);
            if (Constant.COMMON_YES_OR_NO_NO.equals(businessDynamicParam.getSubmit())) {
                //暂存
                datas.put("bus_status", DynamicBusinessConstants.BUSINESS_STATUS_TEMP);
            }else{
                //提交,业务状态置为审批中
                datas.put("bus_status", DynamicBusinessConstants.BUSINESS_STATUS_APPROVING);
            }
        }else {
            datas.put("id", businessDynamicParam.getId());
            datas.put("mod_user", UserUtil.getUser().getId());
            datas.put("mod_time", dateTime);
        }
        datas.put("designer_id", businessDynamicParam.getDesignerId());
        //页面传过来的数据通过表映射处理
        businessDynamicParam.getMain().forEach((key, value) -> {
            datas.put(tableMapping.get("main").get(key), value);
        });
        mainData.setDatas(datas);
        return mainData;
    }

    /**
     * 组织业务子表数据
     * @param key 子表key，据此得出子表名
     * @param mainId 主表数据ID
     * @param value 子表数据
     * @return 子表数据
     */
    private ModelDataEntity getSubFormData(String key, String mainId, List<Map<String, Object>> value, String designerId) throws JsonProcessingException {
        Map<String, Map<String, String>> tableMapping = sysBusinessDesignerService.getMainTableMappingByDesignerId(designerId);
        ModelDataEntity mainData = new ModelDataEntity();
        mainData.setTableName("dyn_" + "sub_" + key);
        List<Map<String, Object>> dataList = value.stream().map(m -> {
            Map<String, Object> colDatas = new HashMap<>();
            colDatas.put("id", UuidUtil.get32UUID());
            colDatas.put("main_id", mainId);
            m.forEach((keyCol, valueCol) -> {
                colDatas.put(tableMapping.get(key).get(keyCol), valueCol);
            });
            return colDatas;
        }).collect(Collectors.toList());
        mainData.setDataList(dataList);
        return mainData;
    }
}
